package org.xiaobai.ai.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.youbenzi.md2.export.FileFactory;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter;
import org.xiaobai.ai.api.domain.request.ChatProcessRequest;
import org.xiaobai.ai.api.enums.ChatMessageTypeEnum;
import org.xiaobai.ai.entity.ChatMessageVO;
import org.xiaobai.ai.entity.ChatPaperDetailVO;
import org.xiaobai.ai.entity.ChatPaperVO;
import org.xiaobai.ai.entity.ChatRoomVO;
import org.xiaobai.ai.mapper.ChatPaperMapper;
import org.xiaobai.ai.request.ChatPaperCreateRequest;
import org.xiaobai.ai.request.ChatPaperGenerateRequest;
import org.xiaobai.ai.request.ChatPaperQueryRequest;
import org.xiaobai.ai.request.ChatUserChatAddRequest;
import org.xiaobai.ai.service.ChatMessageService;
import org.xiaobai.ai.service.ChatPaperDetailService;
import org.xiaobai.ai.service.ChatPaperService;
import org.xiaobai.ai.service.ChatRoomService;
import org.xiaobai.common.entity.BaseEntity;
import org.xiaobai.common.entity.BaseId;
import org.xiaobai.common.utils.UserUtil;
import org.xiaobai.core.exception.TipException;
import org.xiaobai.core.utils.PageUtil;
import org.xiaobai.tool.utils.FileUtil;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

/**
 * @author dingfeng.xiao
 * @description 论文service
 * @date 2023/8/16 10:40
 */
@Service
public class ChatPaperServiceImpl extends ServiceImpl<ChatPaperMapper, ChatPaperVO> implements ChatPaperService {

    @Resource
    private ChatRoomService chatRoomService;

    @Resource
    private ChatMessageService chatMessageService;

    @Resource
    private ChatPaperDetailService chatPaperDetailService;

    @Resource
    private FileUtil fileUtil;

    private static final String PAPER_OUTLINE_PROMPTS_STEP1 = "这句话的返回格式的要求：\n  1、只生成一级标题；\n  2、大纲的一级标题最多10条；\n  3、只返回array数组，不要有多余的其他文字，希望可以直接用JSON.parse解析，格式要有缩进；\n  4、返回的格式例如：[\n    \"引言\",\n    \"环境污染的定义和分类\",\n    \"结论\"\n    ]\n需求正文：\n  请帮我生成一个论文大纲，信息如下：\n  论文的标题是：{};\n  论文需要涵盖下述关键点：{};\n  我希望论文字数在{}字左右。";

    private static final String PAPER_OUTLINE_PROMPTS_STEP2 = "请你结合上面的论文信息，分段写出论文正文。\n    请注意你的回答只包含段落标题和论文正文即可，不要出现多余的话语。\n    下面是你需要输出的本段落内容。\n    本段标题：{}，\n    本段字数：{}左右。";

    @Override
    public Page<ChatPaperVO> paperMy(ChatPaperQueryRequest queryRequest) {
        IPage<ChatPaperVO> categoryPage = page(new Page<>(queryRequest.getPageNum(), queryRequest.getPageSize()),
                new LambdaQueryWrapper<ChatPaperVO>()
                        .eq(ChatPaperVO::getUserId, UserUtil.getUserId())
        .orderByDesc(BaseId::getId));

        return PageUtil.toPage(categoryPage, categoryPage.getRecords());
    }

    @Override
    public Long paperCreate(ChatPaperCreateRequest createRequest) {
        Long chatRoom = chatRoomService.createChatRoom(convertRoomRequest(createRequest));
        ChatPaperVO paperVO = convertPaperRequest(chatRoom, createRequest);
        paperVO.setDelete(0);
        save(paperVO);
        return paperVO.getId();
    }

    @Override
    public ResponseBodyEmitter paperGenerate(ChatPaperGenerateRequest generateRequest) {
        Long paperId = generateRequest.getPaperId();
        String entry = generateRequest.getEntry();
        List<String> outline = generateRequest.getOutline();


        ChatPaperVO chatPaperVO = getById(paperId);
        if (Objects.isNull(chatPaperVO)) {
            throw new TipException("论文信息不存在");
        }
        ChatRoomVO chatRoomVO = chatRoomService.getById(chatPaperVO.getRoomId());
        List<ChatPaperDetailVO> detailList = chatPaperDetailService.findByPaperId(paperId);
        if (CollectionUtils.isEmpty(detailList)) {
            for (int i = 0; i < outline.size(); i++) {
                ChatPaperDetailVO detail = new ChatPaperDetailVO();
                detail.setPaperId(paperId);
                detail.setDelete(0);
                detail.setEntry(outline.get(i));
                detail.setSort(i);
                detailList.add(detail);
            }
            chatPaperDetailService.saveBatch(detailList);
        }
        ChatProcessRequest chatProcessRequest = new ChatProcessRequest();
        chatProcessRequest.setPrompt(StrUtil.format(PAPER_OUTLINE_PROMPTS_STEP2,
                entry,
                chatPaperVO.getWordNum() / detailList.size()));
        chatProcessRequest.setUserId(chatPaperVO.getUserId());
        ChatProcessRequest.Options options = new ChatProcessRequest.Options();
        options.setRoomId(chatPaperVO.getRoomId());

        // 获取最新消息
        ChatMessageVO messageVO = chatMessageService.getOne(new LambdaQueryWrapper<ChatMessageVO>()
                .eq(ChatMessageVO::getChatRoomId, chatPaperVO.getRoomId())
                .eq(ChatMessageVO::getMessageType, ChatMessageTypeEnum.ANSWER)
                .orderByDesc(BaseEntity::getCreateTime)
                .last(" limit 1"));
        options.setConversationId(messageVO.getConversationId());
        options.setParentMessageId(messageVO.getMessageId());
        chatProcessRequest.setOptions(options);
        // 消息接收结束后// 事件
        chatProcessRequest.addFinishConsumer(replyChat -> {
            if (replyChat.startsWith("消息处理异常")) {
                return;
            }
            // 存库
            Optional<ChatPaperDetailVO> first = detailList.stream()
                    .filter(v -> v.getEntry().equals(entry)).findFirst();
            if (first.isPresent()) {
                ChatPaperDetailVO paperDetailVO = first.get();
                paperDetailVO.setContent(replyChat);
                chatPaperDetailService.updateById(paperDetailVO);
            }
        });
        return chatMessageService.sendMessage(chatProcessRequest);
    }

    @Override
    public ResponseBodyEmitter paperStart(Long paperId) {
        ChatPaperVO chatPaperVO = getById(paperId);
        if (Objects.isNull(chatPaperVO)) {
            throw new TipException("论文信息不存在");
        }
        ChatProcessRequest chatProcessRequest = new ChatProcessRequest();
        chatProcessRequest.setPrompt(StrUtil.format(PAPER_OUTLINE_PROMPTS_STEP1,
                chatPaperVO.getTitle(),
                chatPaperVO.getTags(),
                chatPaperVO.getWordNum()));
        chatProcessRequest.setUserId(chatPaperVO.getUserId());
        ChatProcessRequest.Options options = new ChatProcessRequest.Options();
        options.setRoomId(chatPaperVO.getRoomId());
        chatProcessRequest.setOptions(options);
        // 消息接收结束后// 事件
        chatProcessRequest.addFinishConsumer(replyChat -> {

        });
        return chatMessageService.sendMessage(chatProcessRequest);
    }

    @Override
    public String paperExport(Long paperId, String exportType) throws IOException {
        ChatPaperVO chatPaperVO = getById(paperId);
        if (Objects.isNull(chatPaperVO)) {
            throw new TipException("论文信息不存在");
        }

        List<ChatPaperDetailVO> detailList = chatPaperDetailService.findByPaperId(paperId);

        if (CollectionUtils.isEmpty(detailList)) {
            return null;
        }
        StringBuilder text = new StringBuilder();
        text.append("##").append(chatPaperVO.getTitle()).append("\n");
        for (ChatPaperDetailVO detailVO : detailList) {
            if (StrUtil.isNotEmpty(detailVO.getContent())) {
                text.append("\n").append(detailVO.getContent());
            }
        }
        String fileName = chatPaperVO.getTitle() + "-" + new Date().getTime() + "." + exportType;
        FileFactory.produce(text.toString(), fileUtil.getFilePath(fileName, FileUtil.FILE_SUFFIX));

        return fileUtil.getFileUrls(FileUtil.FILE_SUFFIX, fileName);
    }

    private ChatUserChatAddRequest convertRoomRequest(ChatPaperCreateRequest createRequest) {
        ChatUserChatAddRequest request = new ChatUserChatAddRequest();
        request.setUserId(-99L);
        request.setHisNum(30);
        request.setModelId(-1L);
        request.setTitle(createRequest.getTitle());
        request.setDescription(createRequest.getTags());
        return request;
    }

    private ChatPaperVO convertPaperRequest(Long roomId, ChatPaperCreateRequest createRequest) {
        ChatPaperVO chatPaper = new ChatPaperVO();
        chatPaper.setUserId(createRequest.getUserId());
        chatPaper.setTitle(createRequest.getTitle());
        chatPaper.setTags(createRequest.getTags());
        chatPaper.setWordNum(createRequest.getWordNum());
        chatPaper.setRoomId(roomId);
        return chatPaper;
    }
}
